//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
//	File		 :	FormattedOutput.cpp
//	Contents	 :	Source file for class CFormattedOutput, CHTMLFormattedOutput
//	Creation Date:	22/12/1999
//	Last Modified:	23/12/1999	lg
//	tabs width	 :	every 4 characters
//
//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888


#include <stdexcept>
#include <cassert>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include "htmlformattedoutput.h"

#ifdef _MFC_VER	// mfc specific code to follow
#include "msword9.h"
#endif

using std::string;


//_______________________________________________________________________________________
//
//	StreamQueuedText()
//
//		Streams the accumulated text to the stream in the current format
//		This version assumes that most of the text is in the default format and thus does
//			not support nesting of format tags. If this assumption is not true, a more
//			efficient stream might be possible
//		Last modified: lg 1/1/20100
//
//_______________________________________________________________________________________
void CHTMLFormattedOutput::StreamQueuedText()
{
	// must call BeginHeader before add text etc.
	assert(IsInProgress());

	if (!GetQueuedText().length())
		return;

	assert(Format_map_lookup(CurrentFormat) < 10000);
	assert(Format_map_lookup(CurrentFormat) < VecStylesText.size());


	// write style
	StreamText(VecStylesText[Format_map_lookup(CurrentFormat)]);

	// Without the pre tag , must use non-breaking space tag
	StreamText(GetQueuedText());

	// make spaces substitution. Others as well?
	/*
	if (GetQueuedText().find(' ') == string::npos)
	else
	{
		string output;
		const char* queue = GetQueuedText().c_str();
		for (unsigned i = 0; i < GetQueuedText().length(); ++i)
	
			if (queue[i] != ' ')
				output += queue[i];
			else
				output += "&nbsp;";

		StreamText(output);
	}
	*/

	ClearQueuedText();
}

//_______________________________________________________________________________________
//
//	AddNewLine()
//
//		Add new paragraph mark. Word does not imbed the paragraph mark in the middle of
//			the text. Can look into doing that.
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
void CHTMLFormattedOutput::AddNewLine()
{
	// must call BeginHeader before add text etc.
	assert(IsInProgress());
//	<PRE> changes
//	StreamQueuedText();
//	ClearQueuedText();
//	StreamText("<BR>\n");
//	StreamText("\n");
	AddText("\n");
}

void CHTMLFormattedOutput::AddNewLineAndHalf()
{
	AddNewLine();
}

void CHTMLFormattedOutput::AddDoubleNewLines()
{
	AddNewLine();
	AddNewLine();
}

//_______________________________________________________________________________________
//
//	DoBeginHeader()
//
//		Writes the HTML header and a the style sheet if necessary
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
void CHTMLFormattedOutput::DoBeginHeader()
{
	VecStylesText.clear();
	ClearStream();

	StreamText("<HTML>\n<HEAD>\n");


	if (UseStyleSheet)
		CreateStyleSheet();
	CreateStylesText();
	StreamText(	"</HEAD>\n<BODY>\n<P><SAMP>\n"
				"<SPAN style=\"font-style: normal\">"
				"\n<b><PRE>");

	if (!IgnoreFont || !IgnoreFontSize)
	{
		StreamText("<font");
		if (!IgnoreFont)
		{
			StreamText(" face=\"");
			StreamText(GetTextFont());
			StreamText("\"");
		}
		if (!IgnoreFontSize)
		{
			StreamText(" style =\"font-size:");
			char buf[20];
			unsigned intFontSize = GetTextSize() / 10;
			sprintf(buf, "%d.%dpt\"", intFontSize, GetTextSize() - intFontSize * 10);	
		 	StreamText(buf);
		}
		//	<PRE> changes
		StreamText(">\n");
		StreamText(">");
	}
}


void	CHTMLFormattedOutput::CreateStylesText()
{
	if (UseStyleSheet)
	{
		string styleTxt = "</b><b ID=\"" + GetStyleRoot();
		char buf[20];
		for (unsigned i = 0; i < GetFormatsTableSize(); ++i)
		{
			sprintf(buf, "%d", i);	
			VecStylesText.push_back(styleTxt + buf + "\">");
		}
	}
	else
	{
		string styleTxt = "</b><b style=\"";
		const std::vector<CTextFormat>&	formatsTable = GetFormatsTable();
		for (unsigned i = 0; i < formatsTable.size(); ++i)
			VecStylesText.push_back(styleTxt + Format_to_StyleText(formatsTable[i]) + "\">");
	}

}

string CHTMLFormattedOutput::Format_to_StyleText(const CFormattedOutput::CTextFormat& f)
{
	char buf[20];

	// text colour
	string styleStr = "color: #";

	sprintf(buf, "%x", f.TextColour.for_HTML());
	styleStr += buf + 2;

	// background colour
	styleStr+= "; background-color: #";
	sprintf(buf, "%x", f.BackColour.for_HTML());
	styleStr += buf + 2;
	styleStr+= ";";

	// bold
	if (!f.Bold)
		styleStr+= " font-weight: normal;";

	// italic
	if (f.Italic)
		styleStr+= " font-style: italic;";

	return styleStr;
}

void	CHTMLFormattedOutput::CreateStyleSheetData()
{
	const std::vector<CTextFormat>&	formatsTable = GetFormatsTable();
	for (unsigned i = 0; i < formatsTable.size(); ++i)
	{
		char buf[20];
		// ID name
		StreamText("#");
		StreamText(GetStyleRoot());
		sprintf(buf, "%d", i);
		StreamText(buf);

		StreamText("\t{ ");
		StreamText(Format_to_StyleText(formatsTable[i]));
		StreamText("}\n");
	}
}

void	CHTMLFormattedOutput::CreateStyleSheet()
{
	StreamText("<STYLE>\n<!--\n");
	CreateStyleSheetData();
	StreamText("-->\n</STYLE>\n");
}

//_______________________________________________________________________________________
//
//	EndFooter()
//
//		Closes off the HTML stream
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
void CHTMLFormattedOutput::DoEndFooter()
{
	StreamText("</b>\n");
	if (!IgnoreFont)
		StreamText("</font>");
//	<PRE> changes
//	StreamText("</SPAN></SAMP>\n</P>\n</BODY>\n</HTML>");
	StreamText("</SPAN></SAMP></P></PRE></BODY></HTML>");
	
}

unsigned CHTMLFormattedOutput::GetFileFormatCounts()
{
	// copies in both text and html formats
	return 2;
}

#ifdef _MFC_VER	// mfc specific code to follow
//_______________________________________________________________________________________
//
//	GetClipboardFormat()
//
//		returns the Windows HTML and Text clipboard format descriptor unsigned
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
unsigned CHTMLFormattedOutput::GetClipboardFormat(unsigned i)
{
	assert( i < GetFileFormatCounts());
	if (i ==1)
		return RegisterClipboardFormat("HTML Format");
	else
		return CF_TEXT;
}


namespace { enum eADDSTR{ S_BEFORE, S_AFTER, S_OVERWRITE};
unsigned add_txt_to_string(string& str, eADDSTR where, const string& find_str,
																const string& add_str)
{
	unsigned start = str.find(find_str);
	assert(start != string::npos);

	if (start == string::npos)
		return 0;

	if (S_AFTER == where)
		start += find_str.length();

	if (where == S_OVERWRITE)
		str.erase(start, find_str.length());
	str.insert(start, add_str);

	return start;
}
};
//_______________________________________________________________________________________
//
//	GetClipStreamedText
//
//		copies both Windows HTML and Text clipboard formats
//		the html clipboard format has a really tricky header
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
const string& CHTMLFormattedOutput::GetClipStreamedText(unsigned i)
{
	assert( i < GetFileFormatCounts());

	i;
//	if (i == 0)
//		return GetStreamedText(i);
	HTMLClipStream =
		"Version:1.0\nStartHTML:AAAAAAAA\nEndHTML:BBBBBBBB\n"
		"StartFragment:CCCCCCCC\nEndFragment:DDDDDDDD\n";

	HTMLClipStream += HTMLFormattedStream;
	HTMLClipStream += "\n";
	unsigned start	= add_txt_to_string(HTMLClipStream, S_AFTER, "<HTML>", "<!--StartFragment-->");
	unsigned end	= add_txt_to_string(HTMLClipStream, S_BEFORE, "</HTML>", "<!--EndFragment-->");

	char buf[10];

	// write HTML start position to stream
	sprintf(buf, "%08d", HTMLClipStream.find("<HTML>"));
	add_txt_to_string(HTMLClipStream, S_OVERWRITE, string(8, 'A'), buf);

	// write HTML end position to stream
	sprintf(buf, "%08d", HTMLClipStream.length());
	add_txt_to_string(HTMLClipStream, S_OVERWRITE, string(8, 'B'), buf);


	// write fragment start position to stream
	sprintf(buf, "%08d", HTMLClipStream.find("<!--StartFragment"));
	add_txt_to_string(HTMLClipStream, S_OVERWRITE, string(8, 'C'), buf);
	
	// write fragment end position to stream
	sprintf(buf, "%08d", HTMLClipStream.find("<!--EndFragment"));
	add_txt_to_string(HTMLClipStream, S_OVERWRITE, string(8, 'D'), buf);
	return HTMLClipStream;
}
#endif
const string& CHTMLFormattedOutput::GetStreamedText(unsigned)
{
	return HTMLFormattedStream;
}


//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
//	class CHTMLStylesFormattedOutput
//
//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888







#ifdef _MFC_VER	// mfc specific code to follow
unsigned CHTMLStylesFormattedOutput::GetClipboardFormat(unsigned)
{
	return CF_TEXT;
}

unsigned CHTMLStylesFormattedOutput::GetFileFormatCounts()
{
	return 1;
}
const string&  CHTMLStylesFormattedOutput::GetClipStreamedText(unsigned i)
{
	i;
	assert( i < 5GetFileFormatCounts());

	string clipStrm =	"<STYLE>\n<!--\n";
	clipStrm			 += GetHTMLFormattedStream();
	clipStrm			 += "-->\n</STYLE>\n";
	SetHTMLClipStream(clipStrm);
	return GetHTMLClipStream();
}
#endif

void CHTMLStylesFormattedOutput::DoBeginHeader()
{
	ClearStream();
	CreateStyleSheetData();
}

void CHTMLStylesFormattedOutput::DoEndFooter()
{
}

